import json

from django import http
from django.contrib.auth import login, logout
from django.shortcuts import render, redirect
from django.urls import reverse
from django.views import View
from django_redis import get_redis_connection

from apps.carts.utils import mereg_cookie_to_redis
from apps.goods.models import SKU
from apps.users.models import User, Address
import logging
import re

from apps.users.utils import generate_verify_email_url, check_verify_url
from celery_tasks.email.tasks import send_mail_celery
from utils.response_code import RETCODE
from utils.views import LoginRequiredJSONMixin


class Register(View):
    def get(self,request):
        #这里写数据内容,
        return render(request,'register.html')
    # 注册按钮通过表单传参传递过来request.有四个数据.
    def post(self,request):
        data = request.POST
        username = data.get('username')
        password = data.get('password')
        password2 = data.get('password2')
        mobile = data.get('mobile')
        sms_code = data.get('sms_code')

        # 如果四个有一个缺了,就返回错误.
        if not all([username,password,password2,mobile]):
            return http.HttpResponseBadRequest('不对,缺东西')
        if not re.match(r'[a-zA-Z0-9_-]{5,20}',username):
            return http.HttpResponseBadRequest('用户名不对')
        if not re.match(r'[a-zA-Z0-9]{8,20}', password):
            return http.HttpResponseBadRequest('密码不对')
        if password != password2:
            return http.HttpResponseBadRequest('密码不一致')
        if not re.match(r'1[3-9]\d{9}', mobile):
            return http.HttpResponseBadRequest('手机号不符合规则')

        redis_conn = get_redis_connection('code')
        redis_sms_code = redis_conn.get('sms_%s' % mobile)
        if redis_sms_code is None:
            return http.HttpResponseBadRequest("短信验证码 过期了")
        if redis_sms_code.decode() != sms_code:
            return http.HttpResponseBadRequest("短信验证码不一致")

        # 数据入库,为防止出错,设置异常
        try:
            user = User.objects.create_user(username=username,
                                            password=password,
                                            mobile=mobile)

        except Exception as e:
            logger = logging.getLogger('django')
            logger.error(e)
        login(request, user)
        # 使用login方法设置保持登陆状态,根据需求来,现在是要求注册后默认登陆

        # 返回首页,重定向
        return redirect(reverse('contents:index'))


class UsernameView(View):
    def get(self,request,username):
        count = User.objects.filter(username=username).count()
        return http.JsonResponse({'code':0,'errmsg':'ok','count':count})


class MobileView(View):
    def get(self,request,mobile):
        count = User.objects.filter(mobile=mobile).count()
        return http.JsonResponse({'code':0,'errmsg':'ok','count':count})


class LoginView(View):
    # 登陆界面
    def get(self,request):
        return render(request, 'login.html')
    # 校验数据
    def post(self,request):
        username = request.POST.get('username')
        password = request.POST.get('pwd')
        remembered = request.POST.get('remembered')

        if not all([username,password]):
            return http.HttpResponseBadRequest('参数没齐')
        if not re.match(r'[a-zA-Z0-9_-]{5,20}', username):
            return http.HttpResponseBadRequest('用户名不对')
        if not re.match(r'[a-zA-Z0-9]{8,20}', password):
            return http.HttpResponseBadRequest('密码不对')


        from django.contrib.auth import authenticate
        from django.contrib.auth.backends import ModelBackend
        # 如果用户名和密码正确则返回user 实例对象
        # 如果用户名或密码错误则返回None
        user  = authenticate(username=username,password=password)

        if user is None:
            return http.HttpResponseBadRequest('账号或者密码错误')

        # 保持回话状态
        login(request,user)


        # 判断是不是记住登陆
        if remembered == 'on':
        # 如果点了记住登陆,则默认是俩个星期的session过期时间
            request.session.set_expiry(None)
        else:
            # 如果不点记住登陆,则是此次会话结束就过期
            request.session.set_expiry(0)

        response =  redirect(reverse('contents:index'))

        # 设置cookie,让首页显示用户登陆状态
        response.set_cookie('username', user.username, max_age=3600)
        response = mereg_cookie_to_redis(request,user,response)
        return response


class LogoutView(View):
    def get(self,request):
        # request.session.flush
        # 吧状态保持的信息删掉
        from django.contrib.auth import logout
        logout(request)
        # 删除cookie中的username信息

        response =redirect(reverse('contents:index'))
        response.delete_cookie('username')
        # 跳转到首页
        return response

# 用户中心要登陆之后才可以访问
from django.contrib.auth.mixins import LoginRequiredMixin

class UsercenterView(LoginRequiredMixin,View):
    def get(self,request):
        user = request.user
        context ={
            'username' :user.username,
            'mobile':user.mobile,
            'email':user.email,
            'email_active': user.email_active
        }
        return render(request,'user_center_info.html',context=context)
    # 如果没登陆会跳转到http://www.meiduo.site:8000/accounts/login/?next=/center/


"""
当前我们是和前端进行ajax 交互
交互的数据 应该都是JSON数据
但是LoginRequiredMixin 返回的并不是json数据,而是重定向

我们应该返回前端JSON
"""

# 发送邮件
class EmailView(LoginRequiredJSONMixin,View):
    def put(self,request):
        # 接收信息
        body = request.body
        body_str = body.decode()
        data = json.loads(body_str)
        # 验证信息
        email = data.get('email')
        if email is None:
            return http.JsonResponse({'code':RETCODE.PARAMERR,'errmsg':'邮箱为空'})
        if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$',email):
            return http.JsonResponse({'code': RETCODE.EMAILERR, 'errmsg': '参数格式不正确'})

        # 更新数据
        user=request.user
        try:
            user.email=email
            user.save()
        except Exception as e:
            import logging
            logger = logging.getLogger('django')
            logger.error(e)
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '邮箱保存出错'})

        # 发送激活邮件
            # 配置163服务器
            # 在settings中指定EMAIL_HOST和.
            # from django.core.mail import send_mail
            # subject = '美多商城激活邮件'
            # message =‘邮件内容'
            # from_email = '美多商城<qi_rui_hua@163.com>'
            # 发件人
            # recipient_list = [email]
            # # html_message=None可以设置html
            # html_message = " <a href='#'>戳我有惊喜</a>"
            #
            # send_mail(
            #     subject=subject
            # message = message
            # from_email = from_email
            # recipient_list = recipient_list
            # html_message = html_message
            # )

        # 邮件中的内容.
        # from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
        # from meiduo_mall import settings
        # s = Serializer(secret_key=settings.SECRET_KEY,expires_in=3600)
        # data = {'id':user.id}
        # token = s.dumps(data).decode()
        #
        # verify_url = 'http://www.meiduo.site:8000/email_active/?token='+token

        verify_url = generate_verify_email_url(user.id)

        send_mail_celery.delay(email,verify_url)
        # 返回响应
        return  http.JsonResponse({'code':RETCODE.OK,'errmsg':'ok'})

# 激活邮件
class EmailactiveVIew(View):
    def get(self,request):
        # 获取token
        token = request.GET.get('token')
        if token is None:
            return http.HttpResponseBadRequest('token参数错误')
        # 解密
        id_html = check_verify_url(token)
        if id_html is None:
            return http.HttpResponseBadRequest('解析出来的id参数错误')
        # 在数据库中查询
        try:
            user = User.objects.get(id=id_html)
        except Exception:
            return http.HttpResponseBadRequest('没有此用户')

        user.email_active = True
        user.save()

        return redirect(reverse('users:center'))

# 收货地址显示
class UserAddressView(LoginRequiredMixin,View):
    def get(self,request):
        user = request.user
        # 找好几个收货地址对象
        addresses = Address.objects.filter(user=user,is_deleted=False)
        address_list = []
        # 遍历对象,得到收货地址的字典
        for address in addresses:
            address_dict = {
                "id": address.id,
                "title": address.title,
                "receiver": address.receiver,
                "province": address.province.name,
                "province_id": address.province_id,
                "city": address.city.name,
                "city_id": address.city_id,
                "district": address.district.name,
                "district_id": address.district_id,
                "place": address.place,
                "mobile": address.mobile,
                "tel": address.tel,
                "email": address.email
            }
            # 现在列表里是好几个字典
            address_list.append(address_dict)
        #  将这些内容返回给前端.
        context = {
            'default_address_id': user.default_address_id,
            'addresses': address_list,
        }
        return render(request,'user_center_site.html',context=context)

# 新建收货地址
class CreateAddressView(LoginRequiredJSONMixin,View):
    def post(self,request):
        # 判断是否超过20
        count = Address.objects.filter(user=request.user).count()
        if count>20:
            return http.HttpResponseBadRequest('超过20个了')

        json_dict = json.loads(request.body.decode())
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')

        # 校验参数
        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return http.HttpResponseBadRequest('缺少必传参数')
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseBadRequest('参数mobile有误')
        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return http.HttpResponseBadRequest('参数tel有误')
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return http.HttpResponseBadRequest('参数email有误')

        # 在数据库中创建收货地址
        try:
            address=Address.objects.create(user=request.user,
                    title = receiver,
                    receiver = receiver,
                    province_id = province_id,
                    city_id = city_id,
                    district_id = district_id,
                    place = place,
                    mobile = mobile,
                    tel = tel,
                    email = email)
        except Exception:
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '新增地址失败'})

        # 设置默认地址
        if not request.user.default_address:
            request.user.default_address = address
            request.user.save()

        address_dict = {
            "id": address.id,
            "title": address.title,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }

        # 响应保存结果
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '新增地址成功', 'address': address_dict})


# 收货地址的编辑,收货地址的更新
class UpdateAdderssView(LoginRequiredJSONMixin,View):
    def put(self,request,address_id):
        # 接收数据
        json_dict=json.loads(request.body.decode())
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')
        # 2.验证数据
        # 校验参数
        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return http.HttpResponseBadRequest('缺少必传参数')
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseBadRequest('参数mobile有误')
        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return http.HttpResponseBadRequest('参数tel有误')
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return http.HttpResponseBadRequest('参数email有误')

        # 更新数据
        try:
            # 找到选中的那个收货地址,然后进行更新.
            Address.objects.filter(id=address_id).update(
                user=request.user,
                title=receiver,
                receiver=receiver,
                province_id=province_id,
                city_id=city_id,
                district_id=district_id,
                place=place,
                mobile=mobile,
                tel=tel,
                email=email
            )
        except Exception:
            return http.JsonResponse({'code':RETCODE.DBERR,'errmsg':'数据库更新失败'})

        # 需要将更新之后的最新的数据返回给前端
        address = Address.objects.get(id=address_id)
        address={
            "id": address.id,
            "title": address.title,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'ok', 'address': address})


    def delete(self,request,address_id):
        try:
            address = Address.objects.get(id=address_id)
            address.is_deleted=True
            address.save()
        except Exception:
            return http.JsonResponse({'code':RETCODE.DBERR,'errmsg':'删除失败'})

        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'ok'})


"""
一
    用户:点击设为默认,改变默认
    前端:将用户请求通过ajax发给后端,告诉后端是设置哪个为默认地址
    后端:实现用户的请求
二
    1.接受请求.
    2.删除原来的默认地址
    3.设置新的默认地址
三
    确定路由和传参方式
    put   addresses/(?P<address_id>\d+)/default/
"""
# 设置默认收货地址
class SetDefaultView(LoginRequiredJSONMixin,View):
    def put(self,request,address_id):

        try:
            address = Address.objects.get(id=address_id)
            # .2设置默认地址
            request.user.default_address=address
            request.user.save()
        except Exception:
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '设置默认地址失败'})
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '设置默认地址成功'})


"""
一
    用户:点击保存,将输入的数据变为标题
    前端:将用户输入的数据传送给后端
    后端:将前端传来的数据替换了原标题
二
    1.接收数据
    2.更新数据
    3.返回相应
三
    确定路由和传参方式
    put   addresses/(?P<address_id>\d+)/title/
"""

class UpdateTitleView(LoginRequiredJSONMixin,View):
    def put(self,request,address_id):
        json_dict = json.loads(request.body.decode())
        title=json_dict.get('title')
        try:
            address = Address.objects.get(id=address_id)
            address.title=title
            address.save()
        except Exception:
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '设置标题失败'})

        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '设置标题成功'})



"""
一
    用户:输入元密码和新密码
    前端:将用户输入的数据传送给后端
    后端:将前端传来的数据验证并替换
二
    1.接收数据
    2.验证数据
    3.更新数据
    4.退出登陆
    5.返回相应
三
    确定路由和传参方式
    put   addresses/(?P<address_id>\d+)/title/
"""

class ChangePasswordView(LoginRequiredMixin,View):
    def get(self,request):
        return render(request,'user_center_pass.html')

    def post(self,request):
        user=request.user
        old_password=request.POST.get('old_password')
        new_password = request.POST.get('new_password')
        new_password2 = request.POST.get('new_password2')


        if not all([old_password, new_password, new_password2]):
            return http.HttpResponseForbidden('缺少必传参数')
        if not re.match(r'^[0-9A-Za-z]{8,20}$', new_password):
            return http.HttpResponseBadRequest('密码最少8位，最长20位')
        if new_password != new_password2:
            return http.HttpResponseBadRequest('两次输入密码不一致')

       # 验证旧密码是否正确
        if not user.check_password(old_password):
            return render(request,'user_center_pass.html',{'change_password_errmsg': '旧密码错误'})

        # 修改新密码
        try:
            user.set_password(new_password)
            user.save()
        except Exception:
            return render(request,'user_center_pass.html',{'change_password_errmsg': '修改密码失败'})

        logout(request)

        # 跳转到登陆界面
        response = render(request,'login.html')
        response.delete_cookie('username')

        return response



class HistoryView(LoginRequiredJSONMixin,View):
    # 添加浏览记录到redis中
    def post(self,request):
        # 1.必须是登录用户
        user = request.user
        # 2.接收json数据
        data=json.loads(request.body.decode())
        sku_id=data.get('sku_id')
        # 3.判断校验数据
        try:
            sku=SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return http.JsonResponse({'code':RETCODE.NODATAERR,'errmsg':'此商品ID不存在'})
        # 4.连接redis
        redis_conn = get_redis_connection('history')
        # 5.判断去重 lrem
        redis_conn.lrem('history_%s'%user.id,0,sku_id)
        # 6. 添加商品id lpush
        redis_conn.lpush('history_%s'%user.id,sku_id)
        # 7. 对列表裁剪，只保留5条数据 LTRIM
        redis_conn.ltrim('history_%s'%user.id,0,4)
        return http.JsonResponse({'code':RETCODE.OK,'errmsg':'ok'})


    def get(self,request):
        # 1.连接redis
        user = request.user
        redis_conn = get_redis_connection('history')
        # 2. 获取指定用户的redis数据
        ids=redis_conn.lrange('history_%s'%user.id,0,4)
        # 3对商品id遍历，查询商品的详细信息
        sku_list=[]
        for id in ids:
            sku = SKU.objects.get(id=id)
            sku_list.append({
                'id':sku.id,
                'name':sku.name,
                'price':sku.price,
                'default_image_url':sku.default_image.url
            })
        # 4.将对象变成字典
        # 5.返回数据
        return http.JsonResponse({'code':RETCODE.OK,'errmsg':'ok','skus':sku_list})






    #     # 获取浏览的商品id
    #     data=json.loads(request.body.decode())
    #     sku_id=data.get('sku_id')
    #     # 校验商品id是否存在
    #
    #     try:
    #         sku=SKU.objects.get(id=sku_id)
    #     except SKU.DoesNotExist:
    #         return http.JsonResponse({'code':RETCODE.NODATAERR,'errmsg':'不存在此商品'})
    #     # 连接redis
    #     redis_conn=get_redis_connection('history')
    #     # 去重   0表示移除所有值
    #     redis_conn.lrem('history_%s'%request.user.id,0,sku_id)
    #     # 添加商品id
    #     redis_conn.lpush('history_%s'%request.user.id,sku_id)
    #     # 裁剪展示5份
    #     redis_conn.ltrim('history_%s'%request.user.id,0,4)
    #     return http.JsonResponse({'code':RETCODE.OK})
    #
    # # 将浏览记录展示到前端
    # def get(self,request):
    #     user=request.user
    #     # 连接redis
    #     redis_conn = get_redis_connection('history')
    #     # 读取redis中的数据的前五个
    #     ids=redis_conn.lrange('history_%s'%user.id,0,4)
    #     history_list=[]
    #     # 将对象转换成字典
    #     for id in ids:
    #         # 读取商品的信息.
    #         sku=SKU.objects.get(id=id)
    #         # 将商品的信息变成字典存在列表中
    #         history_list.append({
    #             'id':sku.id,
    #             'name':sku.name,
    #             'price':sku.price,
    #             'default_image_url':sku.default_image.url
    #         })
    #     # 返回一个响应
    #     return http.JsonResponse({'code':RETCODE.OK,'errmsg':'ok','skus':history_list})


# base64和pickle结合使用
# carts={'1':{'selected':True,'count':5}}
#  by=pickle.dumps(carts)
#
#  encode=base64.b64encode(by)
#  decode=base64.b64decode(encode)
#
#  pickle.loads(decode)

